/*
 * PBBFileIO.java
 *
 * Created on June 2, 2007, 10:52 AM
 *
 * Basic class to handle file IO.  Based on previous project designs.
 *
 *Copyright 2007-2008 Jon W Huss III

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 *
 * @author Jon Huss
 */

package proteinboxbot;

import java.io.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;

import java.util.*;
import java.security.*;
import java.util.zip.*;
import proteinboxbot.*;


/**
 *
 * @author Jon Huss
 */
public class PBBFileIO {
    
    private File outputFile;
    
    private File inputFile;
    
    private LineNumberReader lnr;
    
    private PrintWriter pw;
    
    private PBBLogging log;
    
    /** Creates a new instance of PBBFileIO */
    public PBBFileIO(PBBLogging l) {
        log = l;
    }
    
    public boolean initOutFile(String outFile) throws IOException{
        //Used to only initialize output
        
        // Check to see if the output file already exists, then
        // deletes/overwrites it.
        if (outFile != null) {
            //System.out.println("creating new file object");
            outputFile = new File(outFile);
        }
        
        if(outputFile.exists()) {
            //System.out.println("deleting file");
            outputFile.delete();
        }
        //System.out.println("creating new directories");
        
        File tmpFile = outputFile.getParentFile();
        if (tmpFile != null){
            tmpFile.mkdirs();
        }
        //System.out.println("creating new file");
        outputFile.createNewFile();
        
        if (outputFile.canWrite()) {
            pw = new PrintWriter(new BufferedWriter(new FileWriter(outputFile)));
        } else{
            System.out.println("Cannot Write to output.");
            return false;
        }
        return true;
        
    }//End initOutput
    
    public boolean writeFileln(String line) throws IOException{
        
        if(outputFile != null) {
            
            if(outputFile.canWrite()){
                if (pw != null) {
                    pw.println(line);
                    return true;
                }
            }
        }
        return false;
    }// end writeFileln()
    
    public String[] getFileLines(String inFile) {
        String line;
        String lineEnd =  System.getProperty("line.separator");
        Vector<String> data = new Vector<String>();
        if (this.initInFile(inFile) == false ) {
            System.out.println("Cannot open input file, " + inFile + " for reading.");
            return null;
        } else {
            try {
                log.addEntry("SYSTEM","FILEIO","Retrieving data from file:"+inFile,PBBLogging.logs.SY);
                //System.out.println("Starting Decoding...");
                line = this.getNextLine();
                while (line != null){
                    data.add(line);
                    line = this.getNextLine();
                }
                log.addEntry("SYSTEM","FILEIO","Finished Retrieving Data.",PBBLogging.logs.SY);
                
            }catch (Exception e){
                System.out.println("Error while opening input file, " + inFile + " for reading:");
                System.out.println(e.getMessage());
                return null;
            }
        }
        String[] tmp = new String[1];
        return data.toArray(tmp);
    }
    
    public String getFileContent(String inFile){
        String line;
        String lineEnd =  System.getProperty("line.separator");
        String data ="";
        if (this.initInFile(inFile) == false ) {
            System.out.println("Cannot open input file, " + inFile + " for reading.");
            return data;
        } else {
            try {
                log.addEntry("SYSTEM","FILEIO","Retrieving data from file:"+inFile,PBBLogging.logs.SY);
                //System.out.println("Starting Decoding...");
                line = this.getNextLine();
                while (line !=null){
                    data = data + line + lineEnd;
                    line = this.getNextLine();
                }
                log.addEntry("SYSTEM","FILEIO","Finished Retrieving Data.",PBBLogging.logs.SY);
                
            }catch (Exception e){
                e.printStackTrace();
                return data;
            }
        }
        return data;
    }
    
    
    public byte[] getFileContentBytes(String inFile) throws IOException{
        String line;
        String lineEnd =  System.getProperty("line.separator");
        
        File inF;
        FileInputStream fis;
        //inF = null;
        if (inFile == null) {
            //System.out.println("creating new file object");
            return null;
        }
        inF = new File(inFile);
        if(inF.canRead()){
            try{
                fis = new FileInputStream(inF);
            } catch(FileNotFoundException fnfe){
                System.out.println("Input File Not Found:" + inFile);
                return null;
            }
        } else{
            System.out.println("Cannot Read input file:" + inFile);
            return null;
        }
        byte[] input = new byte[2048];
        byte[] fullData = new byte[0];
        byte[] tmp = null;
        int numRead;
        while ( (numRead = fis.read(input)) != -1) {
            tmp = fullData;
            fullData = new byte[tmp.length+numRead];
            System.arraycopy(tmp,0,fullData,0,tmp.length);
            System.arraycopy(input,0,fullData,tmp.length,numRead);
        }
        
        return fullData;
    }
    
    
    public static final void dumpDataToFile(String fileName, String data) throws IOException {
        File out;
        out = new File(fileName);
        if (out.exists()){
            out.delete();
        }
        File parent = new File(out.getParent());
        if (parent != null){
            parent.mkdirs();
        }
        out.createNewFile();
        if (out.canWrite()){
            FileWriter fw = new FileWriter(out);
            fw.write(data);
        }
        
    }
    public static final void dumpDataToFile(String fileName, byte[] data) throws IOException {
        File out;
        out = new File(fileName);
        if (out.exists()){
            out.delete();
        }
        File parent = new File(out.getParent());
        if (parent != null){
            parent.mkdirs();
        }
        
        
        out.createNewFile();
        if (out.canWrite()){
            FileOutputStream fos = new FileOutputStream(out);
            
            fos.write(data);
        }
        
    }
    public PBBdata getFileAliases(String inFile, PBBdata data) {
        //used to open a file to read in alias
        String line;
        String[] lineVals;
        if (data == null) {
            data = new PBBdata();
        }
        if (this.initInFile(inFile) == false ) {
            System.out.println("Cannot open alias input file, " + inFile + " for reading.");
            return data;
        } else {
            try {
                log.addEntry("SYSTEM","FILEIO_ALIASES","Decoding Aliases File:"+inFile,PBBLogging.logs.SY);
                
                //System.out.println("Starting Decoding...");
                line = this.getNextLine();
                while( line != null){
                    line = line.trim();
                    //System.out.println(line);
                    lineVals = line.split("\\s+");
                    //comment section
                    if (lineVals.length > 0) {
                        if ("#".compareTo(lineVals[0]) == 0) {
                            //got a comment, skip the rest
                            line = this.getNextLine();
                            continue;
                        }
                    }
                    //expecting 2 values
                    //System.out.println(lineVals.length); //DEBUGXXX
                    if (lineVals.length == 2) {
                        if( "".compareTo(lineVals[0]) != 0 && "".compareTo(lineVals[1]) != 0){
                            //make sure there were no empty string
                            //looks good so ad the alias:
                            data.addAlias(lineVals[0],lineVals[1]);
                        } else {
                            log.addEntry("SYSTEM","FILEIO_ALIASES","Error on line:"+ this.getLN(),PBBLogging.logs.SY);
                            
                            System.out.println("Warning, error in alaises file on line: " + this.getLN());
                        }
                        
                    } else {
                        log.addEntry("SYSTEM","FILEIO_ALIASES","Error on line:"+ this.getLN(),PBBLogging.logs.SY);
                        
                        System.out.println("Warning, error in alaises file on line: " + this.getLN());
                    }
                    line = this.getNextLine();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        return data;
    }
    
    public PBBdata decodeSimple(String inFile, PBBdata data) {
        //used to pull data from a simple format file.  The basic format is:
        //Key Value <Value2> <Value3> ..
        //A "# " at the beginning of the line is a comment
        
        String line;
        String[] lineVals;
        if (data == null) {
            data = new PBBdata();
        }
        if (this.initInFile(inFile) == false ) {
            System.out.println("Cannot open input file, " + inFile + " for reading.");
            return data;
        } else {
            try {
                log.addEntry("SYSTEM","FILEIO","Decoding Simple Format File:"+ inFile,PBBLogging.logs.SY);
                //System.out.println("Starting Decoding...");
                line = this.getNextLine().trim();
                //System.out.println(line);
                while( line != null){
                    line = line.trim();
                    //System.out.println(line); //DEBUG XXX
                    lineVals = line.split(PBBxml.ENTRY_SEPARATOR); //switched to a crazy deliminator
                    if (lineVals.length > 0) {
                        if ("#".compareTo(lineVals[0]) == 0) {
                            //got a comment, skip the rest
                            line = this.getNextLine();
                            continue;
                        }
                    }
                    
                    if (lineVals.length > 1) {
                        //need to make sure there are at least two arguments in a line (key val)
                        
                        //Special handling for the 'Text' field
                        //No Need anymore.
                        //if (lineVals[0].trim().compareTo("Text") == 0){
                        //    //have a text field. need to 'resplit' the line.
                        //    String tmp = line.substring(line.indexOf(',')+1).trim();
                        //    //System.out.println("Adding Text Data from Simple File:" + tmp);
                        //    data.addData("Text",tmp,false);
                        //} else{
                        for (int i = 1; i <lineVals.length; i++){
                            //make sure we skip empty strings
                            if (lineVals[i].compareTo("") != 0){
                                data.addData(lineVals[0].trim(),lineVals[i].trim(),false);
                                //System.out.println("Adding Simple Data:" + lineVals[0].trim() + ", " + lineVals[i].trim()); //DEBUG XXX
                                
                            }
                        }
                        //}
                    }
                    line = this.getNextLine();
                }//end while
            }
            
            catch (Exception e){
                e.printStackTrace();
            }
        }
        
        return data;
    }
    
    //Depricated Method
    public void parseXML(String inXML){
        // Use an instance of ourselves as the SAX event handler
        //PBBxml xmlParser =  new PBBxml(inXML);
        //xmlParser.xmlParse(); //may want to have this return something next time.
        //xmlParser.xmlDomParse();
        
    }
    
    public boolean initInFile(String inFile){
        
        if (inFile != null) {
            //System.out.println("creating new file object");
            inputFile = new File(inFile);
        }
        if(inputFile.canRead()){
            try{
                lnr = new LineNumberReader(new FileReader(inputFile));
            } catch(FileNotFoundException fnfe){
                System.out.println("Input File Not Found:" + inFile);
                return false;
            }
        } else{
            System.out.println("Cannot Read input file:" + inFile);
            return false;
        }
        return true;
    }
    
    /**
     * Gets the line number.
     *
     * @throws IOException  File access error.
     */
    public int getLN() throws IOException{
        if (lnr != null) {
            return lnr.getLineNumber();
        } else {
            return 0;
        }
    }// end getLN()
    
    /**
     * Returns the next line from the input file.
     *
     * @return Next line from the input file. Null if no more lines.
     * @throws IOException  File access error.
     */
    public String getNextLine() throws IOException{
        if (lnr != null) {
            return lnr.readLine();
        } else {
            return null;
        }
    }// end getNextLine()
    
    
    public void killStreams() throws IOException{
        if (pw != null) {
            pw.flush();
            pw.close();
        }
        if (lnr != null) {
            lnr.close();
        }
        outputFile = null;
        inputFile = null;
        
        return;
    }// end killStreams()
    
}
